package com.atguigu.study.utils;

import cn.hutool.core.collection.ListUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;



@FunctionalInterface
interface Foo<T>
{
    public String give(T val);
}

@FunctionalInterface
interface Foo2
{
    public int give(String s1,String s2);
}

@FunctionalInterface
interface Foo3<R>
{
    public R build(Integer id,String name,Integer age);
}

@Setter
@Getter
@NoArgsConstructor
class Person
{
    private Integer id;
    private String  personName;
    private Integer age;

    public Person(Integer id)
    {
        this.id = id;
    }

    public Person(Integer id, String personName, Integer age)
    {
        this.id = id;
        this.personName = personName;
        this.age = age;
    }

    @Override
    public String toString()
    {
        return "Person{" +
                "id=" + id +
                ", personName='" + personName + '\'' +
                ", age=" + age +
                '}';
    }
}


public class MethodRefDemo
{
    public static void main(String[] args)
    {
        List<Integer> list = ListUtil.toList(11,12,13);

        List<Person> personList = list.stream().map(id -> new Person(id)).collect(Collectors.toList());
        personList.forEach(System.out::println);

        personList = list.stream().map(Person::new).collect(Collectors.toList());
        personList.forEach(System.out::println);

    }

    private static void test3()
    {
        //3 类名::实例方法(函数式接口抽象方法的第一个参数是实例方法的调用者，后面的参数是实例方法的参数)
        Person p1 = new Person(1,"z3",13);
        Person p2 = new Person(2,"z4",14);
        Person p3 = new Person(3,"z5",15);
        List<Person> list = ListUtil.toList(p1,p2,p3);

        //3.1 使用lambda (第一个参数是实例方法的调用者,意思：第一个参数person是getPersonName方法的调用者,自己持有)
        List<String> nameString = list.stream().map(person -> person.getPersonName()).collect(Collectors.toList());
        System.out.println("使用lambda:"+nameString);
        //3.2 使用方法引用
        nameString = list.stream().map(Person::getPersonName).collect(Collectors.toList());
        System.out.println("使用方法引用:"+nameString);

        //3 类名::实例方法(函数式接口抽象方法的第一个参数是实例方法的调用者，后面的参数是实例方法的参数)
        BiPredicate<String,String> biPredicate = (x, y) -> x.equals(y);
        System.out.println(biPredicate.test("a","a"));
        biPredicate = String::equals;
        System.out.println(biPredicate.test("a","b"));
    }

    //2 类名::静态方法
    private static void test2()
    {
        //2 类名::静态方法
        List<Integer> list = ListUtil.toList(21,2,-3);

        //2.1 使用lambda
        list.sort((x,y) -> x.compareTo(y));
        System.out.println(list);

        //2.2 使用方法引用
        list = ListUtil.toList(21,2,-3);
        list.sort(Integer::compareTo);
        System.out.println(list);
    }

    //1 对象::实例方法
    private static void test1()
    {
        //1 对象::实例方法
        List<Integer> list = ListUtil.toList(1,2,3);
        //1.1 使用lambda
        list.forEach(i -> System.out.println(i));
        //1.2 使用方法引用
        list.forEach(System.out::println);
    }

    private static void AllCode()
    {
        System.out.println("通过方法引用，函数式接口不再需要程序员自己编写接口实现，而是通过已有的" +
                "方法引用形式来实现具体函数的实现,即methodA正好是lambda体的实现逻辑");
        System.out.println();

        Foo<Integer> result = x -> (x * 2) +"";
        System.out.println("lambda express result: " + result.give(5));

        result = String::valueOf;
        System.out.println("1静态方法引用: " + result.give(10));

        String str = "A";
        result = str::repeat;
        System.out.println("2某个对象的方法引用: " + result.give(5));


        Foo2 result2 = String::compareTo;
        System.out.println("3特定类的方法引用: " + result2.give("z","a"));
        result2 = (x,y) -> {
            if(x.compareTo(y) > 0)
            {
                return 1;
            }else if(x.compareTo(y) < 0){
                return -1;
            }else{
                return 0;
            }
        };
        System.out.println(result2.give("a","a"));


        Foo3<Person> foo3 = Person::new;
        System.out.println("4构造方法引用: " + foo3.build(11, "z3", 25));
    }
}

